﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ZetaPrints.ZetaClient.Business.ThreadSubSytem
{
    /// <summary>
    /// Controls the running threads
    /// </summary>
    public class ThreadManager
    {
        #region private static lock
        /// <summary>
        /// Create a unique key to lock the List
        /// </summary>
        private static string ThreadListLock = "ThreadListLockEntry30c9b3429d8d052f6f577b14156f4a56";
        #endregion


        #region private attributes
        /// <summary>
        /// The List of the running or not threads
        /// </summary>
        private List<ThreadItem> _threadList;
        #endregion


        #region public properties
        /// <summary>
        /// Gets a value indicating the execution status of all the threads under this manager.
        /// Will return true if at least one thread is alive.
        /// </summary>
        public bool AreThreadsAlive
        {
            get
            {
                bool areThreadsAlive = false;

                foreach (ThreadItem threadItem in _threadList)
                {
                    if (threadItem.IsAlive)
                    {
                        areThreadsAlive = true;
                        break;
                    }
                }

                return areThreadsAlive;
            }
        }
        #endregion


        #region constructors
        public ThreadManager()
        {
            _threadList = new List<ThreadItem>();
        }
        #endregion


        #region private methods
        /// <summary>
        /// If an item is already doing what we are asking to be done.
        /// If yes, then we reutrn a true.
        /// </summary>
        /// <param name="orderId"></param>
        /// <param name="threadAction"></param>
        /// <returns></returns>
        private bool IsDuplicate(Guid orderId, ThreadActionOption threadAction)
        {
            bool duplicate  = false;

            lock (ThreadListLock)
            {
                /// using for loop since things can come out from under us
                for (int count = 0; count < _threadList.Count; count++)
                {
                    /// if is the same order id, same action and is still alive we do not allow 
                    /// to run.
                    if ((_threadList[count].OrderId == orderId) &&
                        (_threadList[count].ThreadAction == threadAction) &&
                        (_threadList[count].IsAlive))
                    {
                        duplicate = true;
                        break;
                    }
                }
            }

            return duplicate;
        }
        /// <summary>
        /// Remove the items which are dead
        /// </summary>
        private void CleanUp()
        {
            /// lock it up so no one is going in
            lock (ThreadListLock)
            {
                if (_threadList.Count > 50)
                {
                    int count = 0;

                    while( count < _threadList.Count)
                    {
                        if (!_threadList[count].IsAlive)
                        {
                            _threadList.RemoveAt(count);
                        }
                        else
                        {
                            /// we only move if the item is passes the
                            /// test of been alive
                            count++;
                        }
                    }
                }
            }
        }
        #endregion


        #region public methods
        #region add
        /// <summary>
        /// Adds and checks before adding if the thread is not already running
        /// </summary>
        /// <param name="orderId">A orderid of all zeros will be a system thread</param>
        /// <param name="threadAction">this thread might do</param>
        /// <param name="threadToStart"></param>
        public void AddThread(Guid orderId, ThreadActionOption threadAction, Thread threadToStart)
        {
            CleanUp();

            /// we only add if this is not a duplicate and is not running
            if (!IsDuplicate(orderId, threadAction))
            {
                lock (ThreadListLock)
                {
                    _threadList.Add(new ThreadItem(orderId, threadAction, threadToStart));
                }
            }
        }
        /// <summary>
        /// Adds and checks before adding if the thread is not already running
        /// </summary>
        /// <param name="orderId">A orderid of all zeros will be a system thread</param>
        /// <param name="threadAction">this thread might do</param>
        /// <param name="threadToStart">A thread that has not already been started</param>
        /// <param name="threadParamenter">The parameter going inside this thread</param>
        public void AddThread(Guid orderId, ThreadActionOption threadAction, Thread threadToStart, object threadParamenter)
        {
            CleanUp();

            /// we only add if this is not a duplicate and is not running
            if (!IsDuplicate(orderId, threadAction))
            {
                lock (ThreadListLock)
                {
                    _threadList.Add(new ThreadItem(orderId, threadAction, threadToStart, threadParamenter));
                }
            }
        }
        #endregion
        #region stop
        /// <summary>
        /// Stop all the running threads
        /// </summary>
        public void AbortAllThreads()
        {
            lock (ThreadListLock)
            {
                foreach (ThreadItem threadItem in _threadList)
                {
                    if (threadItem.IsAlive)
                    {
                        threadItem.Abort();
                    }
                }
            }
        }
        /// <summary>
        /// Aborts one type of thread accross the board
        /// </summary>
        /// <param name="threadActionToAbort"></param>
        public void AbortOneKindOfThread(ThreadActionOption threadActionToAbort)
        {
            lock (ThreadListLock)
            {
                for (int count = 0; count < _threadList.Count; count++)
                {
                    if (_threadList[count].ThreadAction == threadActionToAbort)
                    {
                        _threadList[count].Abort();
                    }
                }
            }
        }
        /// <summary>
        /// Aborts a thread by the order id
        /// </summary>
        /// <param name="orderId"></param>
        public void AbortOrderIdThread(Guid orderId)
        {
            lock (ThreadListLock)
            {
                for (int count = 0; count < _threadList.Count; count++)
                {
                    if (_threadList[count].OrderId == orderId)
                    {
                        _threadList[count].Abort();
                    }
                }
            }
        }
        #endregion
        #endregion
    }
}
